Using PHP to send iOS Push Notifications via APNs
Asked Answered
F

4

6

I have implemented Push-Notifications into my Project and everything works fine so far. I've tried sending Notifications through Pusher and this worked out just fine. But I have to send them through PHP, which isn't working yet. I found many old explanations on how to make this happen, but none of them seem to work for me.

This is what I'm trying to work with:

    // APNs Push testen auf Token
$deviceToken = $_GET['key']; // Device-Token

// Payload erstellen und JSON codieren
$payload['aps'] = array('alert' => 'TitleText', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);

$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'certificate.pem';

// Stream erstellen
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'certificate.cer', $apnsCert);

$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if ($apns)
{
  // Nachricht erstellen und senden
  $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
  fwrite($apns, $apnsMessage);

  // Verbindung schliessen
  fclose($apns);
}
else
{
  echo "Fehler!";
  var_dump($error);
  var_dump($errorString);
}
Flory answered 6/1, 2018 at 19:15 Comment(1)
How can i add more Params/Data to the Notification, for example some Action-id so when the user open the notification the App will get that Action-id to perform some function related to it.Melitta
V
9

Try using this php script , make sure that the .pem certificate exits in same path as that php script when you run it , also get a correct device token

 <?php
        /* We are using the sandbox version of the APNS for development. For production
        environments, change this to ssl://gateway.push.apple.com:2195 */
        $apnsServer = 'ssl://gateway.sandbox.push.apple.com:2195';
        /* Make sure this is set to the password that you set for your private key
        when you exported it to the .pem file using openssl on your OS X */
        $privateKeyPassword = '1234';
        /* Put your own message here if you want to */
        $message = 'Welcome to iOS 7 Push Notifications';
        /* Pur your device token here */
        $deviceToken =
        '05924634A8EB6B84437A1E8CE02E6BE6683DEC83FB38680A7DFD6A04C6CC586E';
        /* Replace this with the name of the file that you have placed by your PHP
        script file, containing your private key and certificate that you generated
        earlier */
        $pushCertAndKeyPemFile = 'PushCertificateAndKey.pem';
        $stream = stream_context_create();
        stream_context_set_option($stream,
        'ssl',
        'passphrase',
        $privateKeyPassword);
        stream_context_set_option($stream,
        'ssl',
        'local_cert',
        $pushCertAndKeyPemFile);

        $connectionTimeout = 20;
        $connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
        $connection = stream_socket_client($apnsServer,
        $errorNumber,
        $errorString,
        $connectionTimeout,
        $connectionType,
        $stream);
        if (!$connection){
        echo "Failed to connect to the APNS server. Error no = $errorNumber<br/>";
        exit;
        } else {
        echo "Successfully connected to the APNS. Processing...</br>";
        }
        $messageBody['aps'] = array('alert' => $message,
        'sound' => 'default',
        'badge' => 2,
        );
        $payload = json_encode($messageBody);
        $notification = chr(0) .
        pack('n', 32) .
        pack('H*', $deviceToken) .
        pack('n', strlen($payload)) .
        $payload;
        $wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
        if (!$wroteSuccessfully){
        echo "Could not send the message<br/>";
        }
        else {
        echo "Successfully sent the message<br/>";
        }
        fclose($connection);

  ?>
Vaunt answered 6/1, 2018 at 19:21 Comment(9)
Hey Khan, thanks for the help. It doesn't seem to be working though :/ I get an error with number 0. I have also tried this: ´stream_context_set_option($stream, 'ssl', 'cafile', 'entrust_2048_ca.cer'); ´ which doesnt help either.Flory
Development or distribution ?Vaunt
I used distributionFlory
$apnsServer = 'ssl://gateway.push.apple.com:2195';Vaunt
replace the password with yours $privateKeyPasswordVaunt
After doing everything from scratch again it worked. Thank you!Flory
where can i get the appi key?Irritating
@Sh_Khan I'm trying to get this script to work, here's the things that I've done: run the script with https:// and http://, opened ports 2195 and 2196 to outbound traffic on the server, tested the certificate, password and token with pushtry.com (it works as expected there). What are the other possible missing links that I'm not thinking about? The error that I keep getting is "Failed to connect to the APNS server. Error no = 0".Trudietrudnak
This is a very useful answer, though the code could perhaps be a little better organised. Also, you should change the line pack('n', 32); Apple warns that device identifiers are not a fixed length, what I did was $deviceToken = pack('H*', $deviceToken) then later pack('n', strlen($deviceToken)) . $deviceToken to build the message with a potentially variable-length token.Blandish
A
4

Here is new updates on script, As Apple changed notification url:

<?php
    if ( defined("CURL_VERSION_HTTP2") && (curl_version()["features"] & CURL_VERSION_HTTP2) !== 0) {
        $ch = curl_init();
        $body ['aps'] = array (
            "alert" => array (
                "title"  => "hii",
            ),
            "sound"  => "default"
        );
        $curlconfig = array(
            CURLOPT_URL => "https://api.development.push.apple.com/3/device/device_token",
            CURLOPT_RETURNTRANSFER =>true,
            CURLOPT_POSTFIELDS => json_encode($body),
            CURLOPT_SSLCERT =>"apns.pem",
            CURLOPT_SSLCERTPASSWD => "123456",
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
            CURLOPT_VERBOSE => true
        );
        curl_setopt_array($ch, $curlconfig);
        $res = curl_exec($ch);
        if ($res === FALSE) {
                echo('Curl failed: ' . curl_error($ch));
        }
        curl_close($ch);
    }else{
        echo "No HTTP/2 support on client.";
    }
       
    ?>
Alwyn answered 8/7, 2021 at 11:54 Comment(4)
Where is the device Token?Amaryllis
@KrishnaKarki you have to ask the user for push notification, and if he accepts, you get the device token, and you use it in CURLOPT_URL "/device_token"Tsana
Message: Use of undefined constant FRW_CONFIG_DIR - assumed 'FRW_CONFIG_DIR' (this will throw an Error in a a future version of PHP)Dietitian
getting this. Any solutionDietitian
H
2
<?php

    function sendFCM($body, $title, $id, $StudentAdmissionId, $activitytype) {
        $url = "https://fcm.googleapis.com/fcm/send";
        $token = $id;
        $serverKey = 'AAAA8XYL2Y8:APA91bF1fsddfgffdssdsdfsdsdsda8zyWJTgs0OSeiRlk9WQqLwKn51VkMH_XSbpRuiCTU-Fdi2hoV8JY8ST7gCBQe4dlMFASDbr5Oci1bLmg9tyl5dlxyFDauWWCMItUNdFGWO_CWhpHwSIbvbqYwlCnoRd7ucB';
        $notification = array(
            'title' => $title,
            'text' => $body,
            'sound' => 'default',
            'badge' => 1,
            'category' => $activitytype,
            'content-available' => 1
        );
        $arrayToSend = array(
            'to' => $token,
            'notification' => $notification,
            'priority' => 'high'
        );
        $json = json_encode($arrayToSend);
        $headers = array();
        $headers[] = 'Content-Type: application/json';
        $headers[] = 'Authorization: key=' . $serverKey;
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        //Send the request
        echo $response = curl_exec($ch);
        //Close request
        if ($response === FALSE) {
            die('FCM Send Error: ' . curl_error($ch));
        }
        curl_close($ch);
        mysql_query("INSERT INTO `tbl_notifications`(`n_activity_name`,`n_user_id`,`n_device_id`, `n_notification`) VALUES ('$activitytype','$StudentAdmissionId','$id','$response')");
        // #Echo Result Of FireBase Server
        return $response;
    }

?>
  • Use this for php & mysql backend for pusihing notification on android and ios on the same time

  • Here token of apns server is stored in db and pass to send fcm

Honeyman answered 7/3, 2019 at 6:19 Comment(2)
This code works perfect!Kuomintang
@Kuomintang does it works for Killed State tooCyte
R
1

My solution:

$token = 'your device token';
$apns_topic = 'your bundle id';
$apns_pem = 'your location and name of your pem file';
$apns_pass = 'your password' // empty string if nopass
$body = array(
    'aps' => array(
        'alert' => $text,
        'sound' => 'default'
     )
); // Or the other bodies mentioned above

$ch = curl_init("https://api.development.push.apple.com/3/device/$token");
// https://api.push.apple.com/3/device/ in production
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apns-topic: " . $apns_topic));
curl_setopt($ch, CURLOPT_SSLCERT, _FRW_CONFIG_DIR_ . $apns_pem);
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $apns_pass);
$result = curl_exec($ch);
Recalesce answered 16/6, 2022 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.